﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using DomainDriver.CommonUtilities.Collections;
using DomainDriver.DomainModeling.DomainObjects;
using AutomotivePricingModel.ValueObjects.MissingValueOptions;

namespace AutomotivePricingModel.ValueObjects.YearlyFinancialAssessments
{
    public partial class YearlyFinancialAssessment : KeyedDomainObjectBase<Guid, YearlyFinancialAssessment>
    {
        private Dictionary<int, YearValueObservation> m_YearlyObservations;
        private MissingValueOptionEnum m_MissingValueOption;

        public YearlyFinancialAssessment()
        {
            m_Key = Guid.NewGuid();
            m_YearlyObservations = new Dictionary<int, YearValueObservation>();
            m_MissingValueOption = MissingValueOptionEnum.Zero;
        }

        public MissingValueOptionEnum MissingValueOption
        {
            get { return m_MissingValueOption; }
            set { m_MissingValueOption = value; }
        }

        public bool HasValue(int year)
        {
            return m_YearlyObservations.ContainsKey(year);
        }

        public Nullable<double> GetNullableValue(int year)
        {
            if (!m_YearlyObservations.ContainsKey(year))
            { return GetMissingValue(); }
            return m_YearlyObservations[year].Value;
        }

        public double GetValue(int year)
        {
            Nullable<double> value = GetNullableValue(year);
            if (!value.HasValue)
            { throw new ApplicationException(); }
            return value.Value;
        }

        public void SetValue(int year, double value)
        {
            if (!m_YearlyObservations.ContainsKey(year))
            {
                YearValueObservation observation = new YearValueObservation(year, value, m_Key);
                m_YearlyObservations.Add(year, observation);
            }
            else
            { m_YearlyObservations[year].Value = value; }
        }

        public void RemoveValue(int year)
        {
            if (!m_YearlyObservations.ContainsKey(year))
            { throw new ApplicationException(); }
            m_YearlyObservations.Remove(year);
        }

        private Nullable<double> GetMissingValue()
        {
            if (m_MissingValueOption == MissingValueOptionEnum.Zero)
            { return 0; }
            return null;
        }

        public IDictionary<int, double> ActualObservations
        {
            get
            {
                Dictionary<int, double> observations = new Dictionary<int, double>();
                foreach (YearValueObservation observation in m_YearlyObservations.Values)
                {
                    observations.Add(observation.Year, observation.Value);
                }
                return observations;
            }
        }

        #region DomainObject Methods

        public override YearlyFinancialAssessment Copy()
        {
            YearlyFinancialAssessment copy = new YearlyFinancialAssessment();
            CopyTo(copy);
            return copy;
        }

        public override void CopyTo(YearlyFinancialAssessment otherObject)
        {
            if (otherObject.m_Key != m_Key)
            { otherObject.m_Key = m_Key; }
            if (otherObject.m_MissingValueOption != m_MissingValueOption)
            { otherObject.m_MissingValueOption = m_MissingValueOption; }
            CopyDictionaryToOtherInPlace<int, YearValueObservation>(otherObject, (YearValueObservation obs) => obs.Year, (YearlyFinancialAssessment obj) => obj.m_YearlyObservations);
        }

        public override bool Equals(YearlyFinancialAssessment otherObject)
        {
            if (otherObject.m_Key != m_Key)
            { return false; }
            if (otherObject.m_MissingValueOption != m_MissingValueOption)
            { return false; }
            if (!CollectionUtilities.AreUnorderedDictionariesEqual<int, YearValueObservation>(otherObject.m_YearlyObservations, m_YearlyObservations))
            { return false; }
            return true;
        }

        #endregion
    }
}